/**
 * 
 */
package soa.security.mgr.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.ldaptive.SearchScope;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import soa.security.Constants;
import soa.security.domain.*;
import soa.security.domain.Person.Persons;
import soa.security.exception.AdapterException;
import soa.security.exception.OrganizationException;
import soa.security.mgr.service.DepartmentMgrService;
import soa.security.mgr.service.PersonMgrService;
import soa.security.util.BeanUtils;
import soa.security.util.JaxbUtils;

import javax.annotation.Resource;
import javax.naming.Name;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author Cre.Gu
 *
 */
@Service
public class PersonMgrServiceImpl extends BaseMgrServiceImpl implements
		PersonMgrService {
	protected final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(this.getClass());
	@Resource
	protected DepartmentMgrService departmentMgrService;

	@Override
	public void addPerson(String organizationId, Person person)
			throws OrganizationException {
		try {
			if (StringUtils.isBlank(person.getUid())) {
				person.setUid("PE" + findMaxNumber(Person.class));
			}
			validate(person);
			validateOrganization(organizationId);

			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.PERSON);

			person.setDn(person.buildDn(unit.getDn()));
			personDao.create(person);
		} catch (Exception e) {
			wrapException(e);
		}
	}
	
	@Override
	public void addPersonRe(String organizationId, Person person, Department dep)
			throws OrganizationException {
		try {
			if (StringUtils.isBlank(person.getUid())) {
				person.setUid("PE" + findMaxNumber(Person.class));
			}
			validate(person);
			validateOrganization(organizationId);

			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.PERSON);

			person.setDn(person.buildDn(unit.getDn()));
			personDao.create(person);
			
			addOrRemoveDepartments4Mgr(organizationId, person, dep.getDn().toString());
		} catch (Exception e) {
			wrapException(e);
		}
	}

	@Override
	public void updatePerson(String organizationId, Person person)
			throws OrganizationException {
		try {
			validateOrganization(organizationId);
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.PERSON);
			validatePerson(unit.getDn().toString(), person.getUid());
			
			person.setDn(person.buildDn(unit.getDn()));

			Person up = personDao.findByPrimaryKey(unit.getDn()
					.toString(), person.getUid());
			BeanUtils.copyPropertiesWithoutNull(person, up);
			person = up;
			
			validate(person);
			person.setDn(person.buildDn(unit.getDn()));
			personDao.update(person);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	public static void validate(Person person) {
		Assert.hasText(person.getUid(), "人员编码不能为空");
		Assert.hasText(person.getName(), "人员名称不能为空");

		BeanUtils.blank2Null(person);
	}

	@Override
	public List<Person> allPersons(String organizationId)
			throws OrganizationException {
		return allPersons(organizationId, null, false);
	}

	@Override
	public List<Person> allPersons(String organizationId,
			Map<String, Object> parameters, boolean subTree)
			throws OrganizationException {
		List<Person> results = new ArrayList<Person>();
		try {
			validateOrganization(organizationId);

			if (subTree) {
				List<Organization> oneOrg = oneOrg(organizationId);
				for (Organization or : oneOrg) {
					results.addAll(doAllPersons(or.getBid(), parameters));
				}
			} else {
				results = doAllPersons(organizationId, parameters);
			}

		} catch (Exception e) {
			wrapException(e);
		}
		return results;
	}
	
	@Override
	public Page<Person> allPersons(String organizationId, Map<String, Object> parameters, boolean subTree,
			PageRequest request) throws OrganizationException {
		// TODO Auto-generated method stub
		try {
			validateOrganization(organizationId);
			String DN = "";
			if (subTree) {//查询子机构(获取机构DN)
				Organization org = findOrganization(organizationId);
				DN = org.getDn().toString();
			} else {//机构账户组DN
				OrganizationUnit unit = gainOrganizationUnit(organizationId, Constants.PERSON);
				DN = unit.getDn().toString();
			}
			
			Page<Person> page = personDao.allPersons(DN, SearchScope.SUBTREE, parameters, request);
			
			System.out.println(page.getTotalElements());
			System.out.println(page.getTotalPages());
			for (Person a : page.getContent()) {
				System.out.println(a.getDn());
			}
			return page;
		} catch (Exception e) {
			wrapException(e);
		}
		return null;
	}

	protected List<Person> doAllPersons(String organizationId,
			Map<String, Object> parameters) {
		List<Person> results = new ArrayList<Person>();

		OrganizationUnit unit = gainOrganizationUnit(organizationId,
				Constants.PERSON);
		results = personDao.allPersons(unit.getDn().toString(),
				defaultSearchScope, parameters);

		sortResult(results);
		return results;
	}

	@Override
	public List<Person> allPersonsOnlyInOrganization(String organizationId) {
		List<Person> results = new ArrayList<Person>();
		try {
			List<Person> all = allPersons(organizationId);
			List<Department> allDes = departmentAllDepartments(organizationId);

			List<Person> filters = new ArrayList<Person>();
			for (Department department : allDes) {
				filters.addAll(departmentAllPersons(organizationId,
						department.getBid()));
			}

			results.addAll(filterPersons(all, filters, organizationId));
		} catch (Exception e) {
			printException(e);
		}
		return results;
	}

	@Override
	public List<Person> allPersons(List<Person> all, List<Person> deptPersons) {
		Iterator<Person> iter = all.iterator();
		while (iter.hasNext()) {
			Person p = iter.next();
			boolean re = true;
			for (Person person : deptPersons) {
				if (p.getUid().equals(person.getUid())) {
					re = false;
					break;
				}
			}

			if (re)
				iter.remove();
		}
		return all;
	}
	
	@Override
	public Page<Person> allPersons(List<Person> all, List<Person> deptPersons, PageRequest request) {
		// TODO Auto-generated method stub
		Iterator<Person> iter = all.iterator();
		while (iter.hasNext()) {
			Person p = iter.next();
			boolean re = true;
			for (Person person : deptPersons) {
				if (p.getUid().equals(person.getUid())) {
					re = false;
					break;
				}
			}
			if (re)
				iter.remove();
		}
		try {
			//分页数据处理
			List<Person> list = new ArrayList<Person>();
			
			int total = all.size();	//总数
			
			if (total != 0) {
				int pageSize = request.getPageSize();	//每页数
				int pageNumber = request.getPageNumber();	//当前页码
				
				int totalPageNum = getThreadNum(total, pageSize);	//总页数
				
				int start = (pageNumber - 1)*pageSize + 1;	//起始点
				int end = 0;								//结束点
				if (pageNumber == totalPageNum) {
					//访问最后一页(当前页码=总页数)
					end = total;
				} else {
					end = pageNumber*pageSize;
				}
				
				//获取分页的person对象
				//System.out.println(start + " - " + end);
				for (int i = start; i <= end; i++) {
					list.add(all.get(i - 1));
				}
			}
			return new PageImpl(list, request, total);
		} catch (Exception e) {
			// TODO: handle exception
			wrapException(e);
		}
		return null;
	}
	
	/**
	 * 计算总页数
	 * @param total 数据总量
	 * @param commitSize	每页显示多少数据
	 * @return int
	 */
	public int getThreadNum(int total, int commitSize) {
		int num = total % commitSize;
		if (num == 0) {
			return total / commitSize;
		} else {
			return total / commitSize + 1;
		}
	}

	@Override
	public List<Person> getPerson(String organizationId, String personId)
			throws OrganizationException {
		List<Person> list = new ArrayList<Person>();
		try {
			validateOrganization(organizationId);
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.PERSON);
			validatePerson(unit.getDn().toString(), personId);

			Name dn = LdapNameBuilder.newInstance(unit.getDn())
					.add(Constants.UID, personId).build();
			list.add(personDao.findByDn(dn.toString()));

		} catch (Exception e) {
			wrapException(e);
		}
		return list;
	}

	@Override
	public List<Person> adapt(String xml) throws AdapterException {
		try {
			Persons bs = JaxbUtils.xml2Object(xml, Persons.class);
			return bs.getPerson();

		} catch (Exception e) {
			if (log.isDebugEnabled())
				log.debug("格式转换错误", e);
			throw new AdapterException(AdapterException.ERROR_01);
		}
	}

	@Override
	public String unadapt(List<Person> list) throws AdapterException {
		try {
			Persons bs = new Persons();
			bs.addAll(list);

			return JaxbUtils.object2Xml(bs, Persons.class);
		} catch (Exception e) {
			if (log.isDebugEnabled())
				log.debug("格式转换错误", e);
			throw new AdapterException(AdapterException.ERROR_01);
		}
	}

	@Override
	public Person findByDn(String dn) throws OrganizationException {
		try {
			if (StringUtils.isBlank(dn))
				return null;

			return personDao.findByDn(dn);

		} catch (Exception e) {
			printException(e);
			if (log.isDebugEnabled())
				log.debug("错误信息", e);

			return null;
		}
	}

	@Override
	public boolean deleteByDn(String dn) throws OrganizationException {
		try {
			personDao.deleteByDn(dn);
			return true;
		} catch (Exception e) {
			printException(e);
			if (log.isDebugEnabled())
				log.debug("错误信息", e);

			return false;
		}
	}

	@Override
	public List<Person> filterPersons(List<Person> all, List<Person> filters,
			String organizationId) {
		List<Person> results = new ArrayList<Person>();
		try {

			Iterator<Person> iterator = all.iterator();
			while (iterator.hasNext()) {

				Person a = iterator.next();
				for (Iterator<Person> iterator2 = filters.iterator(); iterator2
						.hasNext();) {
					Person f = iterator2.next();

					if (a.getUid().equals(f.getUid())) {
						iterator.remove();
						break;
					}
				}
				findDepartmentName(organizationId, a);
			}

			results.addAll(all);
		} catch (Exception e) {
			printException(e);
		}
		return results;
	}

	@Override
	public Person findByUid(String uid, String organizationId) {
		Person result = new Person();
		try {
			validateOrganization(organizationId);

			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.PERSON);

			return personDao.findByPrimaryKey(unit.getDn().toString(), uid);
		} catch (Exception e) {
			printException(e);
		}
		return result;
	}

	private void findDepartmentName(String organizationId, Person person) {
		List<Department> checked = findDepartments(organizationId,
				Constants.PERSONS, person.getDn().toString());

		String[] nn = new String[checked.size()];
		String[] nn2 = new String[checked.size()];
		int i = 0, j = 0;
		for (Department department : checked) {
			nn[i++] = department.getName();
			nn2[j++] = department.getBid();
		}
		person.setDepartmentName(StringUtils.join(nn, ","));
		person.setDepartmentId(StringUtils.join(nn2, ","));
	}

	@Override
	public List<Group> findGroups(String organizationId, String dn) {
		List<Group> results = new ArrayList<Group>();
		try {
			if (StringUtils.isBlank(dn))
				return results;
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.GROUP);

			results.addAll(groupDao.findAllByAttr(unit.getDn().toString(),
					defaultSearchScope, Constants.PERSONS, dn));
		} catch (Exception e) {
			printException(e);
		}
		return results;
	}

	@Override
	public List<Position> findPositions(String organizationId, String dn) {
		List<Position> results = new ArrayList<Position>();
		try {
			if (StringUtils.isBlank(dn))
				return results;
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.POSITION);

			results.addAll(positionDao.findAllByAttr(unit.getDn().toString(),
					defaultSearchScope, Constants.PERSONS, dn));
		} catch (Exception e) {
			printException(e);
		}
		return results;
	}

	@Override
	public void addPerson4Mgr(String organizationId, Person model,
			String departmentDns, String positionDns, String groupDns)
			throws OrganizationException {
		try {
			addPerson(organizationId, model);

			addOrRemoveDepartments4Mgr(organizationId, model, departmentDns);
			addOrRemovePositions4Mgr(organizationId, model, positionDns);
			addOrRemoveGroups4Mgr(organizationId, model, groupDns);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	@Override
	public void updatePerson4Mgr(String organizationId, Person model,
			String departmentDns, String positionDns, String groupDns)
			throws OrganizationException {
		try {
			updatePerson(organizationId, model);

			addOrRemoveDepartments4Mgr(organizationId, model, departmentDns);
			addOrRemovePositions4Mgr(organizationId, model, positionDns);
			addOrRemoveGroups4Mgr(organizationId, model, groupDns);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	private void addOrRemoveDepartments4Mgr(String organizationId,
			Person person, String departmentDns) {
		// 原来的departmentDns
		List<String> origs = allDepartmentsDns(findDepartments(organizationId,
				Constants.PERSONS, person.getDn().toString()));
		// form 提交的departmentDns
		List<String> forms = formIds(departmentDns);

		// 要增加的departmentDns
		List<String> adds = addIds(origs, forms);
		// 要删除的departmentDns
		List<String> rems = removeIds(origs, forms);

		ldapAddAttrName(adds, Constants.PERSONS, person.getDn().toString());
		ldapRemoveAttrName(rems, Constants.PERSONS, person.getDn().toString());
	}

	private void addOrRemovePositions4Mgr(String organizationId, Person person,
			String positionDns) {
		// 原来的positionDns
		List<String> origs = allPositionsDns(findPositions(organizationId,
				person.getDn().toString()));

		// form 提交的positionDns
		List<String> forms = formIds(positionDns);

		// 要增加的positionDns
		List<String> adds = addIds(origs, forms);
		// 要删除的positionDns
		List<String> rems = removeIds(origs, forms);

		ldapAddAttrName(adds, Constants.PERSONS, person.getDn().toString());
		ldapRemoveAttrName(rems, Constants.PERSONS, person.getDn().toString());
	}

	private void addOrRemoveGroups4Mgr(String organizationId, Person person,
			String groupDns) {
		// 原来的groupDns
		List<String> origs = allGroupsDns(findGroups(organizationId, person
				.getDn().toString()));

		// form 提交的groupDns
		List<String> forms = formIds(groupDns);

		// 要增加的groupDns
		List<String> adds = addIds(origs, forms);
		// 要删除的groupDns
		List<String> rems = removeIds(origs, forms);

		ldapAddAttrName(adds, Constants.PERSONS, person.getDn().toString());
		ldapRemoveAttrName(rems, Constants.PERSONS, person.getDn().toString());
	}

	@Override
	public void remove(String organizationId, String dn) {
		String[] dns = StringUtils.split(dn, ";");
		if (dns == null)
			return;

		for (String string : dns) {
			DirContextOperations context = ldapTemplate.lookupContext(string);

			context.setAttributeValue(Constants.DELETED, Constants.TRUE);
			ldapTemplate.modifyAttributes(context);

			// 删除关系
			// 部门，岗位，用户组
			List<String> rems = new ArrayList<String>();
			rems.addAll(allDepartmentsDns(findDepartments(organizationId,
					Constants.PERSONS, dn)));
			rems.addAll(allPositionsDns(findPositions(organizationId, dn)));
			rems.addAll(allGroupsDns(findGroups(organizationId, dn)));

			ldapRemoveAttrName(rems, Constants.PERSONS, dn);
		}
	}

	@Override
	public Organization belongs(Person person) {
		try {
			String dn = person.getDn().toString();
			String orDn = StringUtils.substringAfter(
					StringUtils.substringAfter(dn, ","), ",");
			return organizationDao.findByDn(orDn);
		} catch (Exception e) {
			return null;
		}
	}
	
	@Override
	public List<Person> findByOrgAndName(String organizationId, String cname) {
		// TODO Auto-generated method stub
		List<Person> results = new ArrayList<Person>();
		try {
			validateOrganization(organizationId);

			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.PERSON);
			results = personDao.findByOrgAndName(unit.getDn().toString(), defaultSearchScope, cname);
			sortResult(results);

		} catch (Exception e) {
			wrapException(e);
		}
		return results;
	}

	
}
